﻿<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <link href="http://sstatic.net/so/all.css" rel="stylesheet" />

    <script src="scripts/Soapi.js" type="text/javascript"></script>

    <style type="text/css">
        body {
            margin-top: 2.5em;
        }
        .separator {
            border-bottom: solid 1px black;
            clear: both;
        }
        .user-info {
            width: 220px;
            float: left;
            margin: 6px;
        }
        .site-icon {
            width: 32px;
            height: 32px;
            opacity: .5;
            filter: alpha(opacity=50);
        }
        #footer {
            background-color: #EEEEEE;
            color: Black;
        }
        .footerdiv {
            margin: 6px;
        }
        .copyright {
            margin-top: 10px;
            color: #3366CC;
        }
        .associated-user {
            float: left;
            clear: both;
            border: solid 1px silver;
            margin: 2px;
        }
    </style>

    <script type="text/javascript">

        // TODO: stage the rendering to enable sorting by display_name/reputation

        // Soapi JavaScript Library RC2 Version 0.9 Revision 2010.06.29.001
        // http://soapi.info/
        // 
        // Copyright 2010, Sky Sanders
        // Dual licensed under the MIT or GPL Version 2 licenses.
        // http://soapi.info/code/js/license.aspx
        // 
        // Date: 7/7/2010 10:17:46 PM
        // Version: RC2.3 0.9 2010.06.29.001
        //-------------------------------------------------------------------------------


        /************************************************************************************************************************
        * Just in case we are in IE and the user has not loaded
        * firebug lite with the footer link
        */
        if ("undefined" === typeof window.console)
        {
            window.console = {
                "log": function() { }
            };
        };


        var sites = [];
        var apiKey = 'qgAq_KfDu0KYzlNG-qaTuw';
        var currentUserName;
        var associatedUsersDiv;
        var unassociatedUsersDiv;


        console.log("fetching sites");

        Soapi.RouteFactory("", apiKey).Sites().getResponse(function(data)
        {
            console.log("sites fetched");
            sites = data.items;
            data = null;
        });


        var cancel = false;
        function cancelSearch()
        {
            cancel = true;
            Soapi.RequestQueue.clear();
        };

        function doSearch()
        {
            cancel = false;

            associatedUsersDiv = document.getElementById("associated-users");
            associatedUsersDiv.innerHTML = "";
            unassociatedUsersDiv = document.getElementById("unassociated-users");
            unassociatedUsersDiv.innerHTML = "";
            var exactMatch = document.getElementById("exact-match").checked;
            var userName = document.getElementById("user-name").value.toUpperCase();

            var unassociatedUsers = [];
            var associationIds = {};


            for (var i = 0; i < sites.length; i++)
            {
                var site = sites[i];

                console.log("searching %s for '%s' " + (exactMatch ? " exact" : ""), site.name, userName);

                var params = exactMatch
                ? { pagesize: 50, min: userName, max: userName, sort: Soapi.Domain.UserSort.name }
                : { pagesize: 50, filter: userName };

                Soapi.RouteFactory(site.api_endpoint, apiKey)
                .Users(params)
                .getResponse(function(data, site)
                {

                    console.log("%s returned %i results", site.name, data.items.length);
                    setMaskMessage(site.name + " returned " + data.items.length + " results");
                    for (var i = 0; i < data.items.length; i++)
                    {

                        var user = data.items[i]
                        user.on_site = site;

                        if (user.association_id)
                        {
                            if (!(user.association_id in associationIds))
                            {
                                if (cancel)
                                {
                                    continue;
                                };
                                associationIds[user.association_id] = user.association_id;
                                setMaskMessage("Loading association " + user.association_id);
                                console.log("Loading association %s", user.association_id);
                                Soapi.RouteFactory("", apiKey)
                                .UsersByIdAssociated(user.association_id)
                                .getResponse(function(association, association_id)
                                {

                                    var associatedUserDiv = document.createElement("div");
                                    associatedUserDiv.title = "assocition id: " + association_id;
                                    associatedUserDiv.className = "associated-user";

                                    associatedUsersDiv.appendChild(associatedUserDiv);
                                    for (var j = 0; j < association.items.length; j++)
                                    {
                                        var user = association.items[j];
                                        var userDiv = renderUserInfo(user);
                                        userDiv.style.styleFloat = "";
                                        userDiv.style.cssFloat = "";
                                        associatedUserDiv.appendChild(userDiv);

                                    };
                                    setMaskMessage("Association " + association_id + " loaded");
                                    console.log("Association %s loaded", association_id);
                                }, null, null, user.association_id);
                            };
                        }
                        else
                        {
                            unassociatedUsersDiv.appendChild(renderUserInfo(user));
                        };
                    }
                }, null, null, site);
            };



        };

        /************************************************************************************************************************
        * A cheap auto loading mask by overriding the queue events
        * Whenever the queue goes active or complete, wait 100ms
        * to make sure the event is not transient and then check
        * the queue length and show/hide mask as indicated.
        * could use jQuery/BlockUI
        */

        Soapi.Events.onQueueActive = Soapi.Events.onQueueComplete = checkMask;

        function checkMask()
        {
            // want a little buffer to eliminate mask flicker
            window.setTimeout(function()
            {
                if (Soapi.RequestQueue.getLength() == 0)
                {
                    unmask();
                }
                else
                {
                    mask();
                };
            }, 100);
        };

        function setMaskMessage(value)
        {
            document.getElementById("loading-mask-message").innerHTML = value || "Please Wait...";

        };
        function mask()
        {
            var loadingMask = document.getElementById("loading-mask");
            loadingMask.style.display = 'block';
            document.getElementById("find-user-button").disabled = true;
        };

        function unmask()
        {
            document.getElementById("loading-mask").style.display = 'none';
            document.getElementById("find-user-button").disabled = false;
            setMaskMessage();
        };
        // end loading mask code


        /************************************************************************************************************************
        * A simple template for the user info
        * could use jQUery/jQote
        */
        function renderUserInfo(user)
        {
            var userdiv = document.createElement("div");
            userdiv.className = "user-info";

            var userReputationAbbreviated = user.reputation >= 10000 ? (Math.round((user.reputation / 1000) * 10) / 10) + "k" : user.reputation;
            var userGravatar = "http://www.gravatar.com/avatar/" + user.email_hash + "?s=32&amp;d=identicon&amp;r=PG";
            var href = user.on_site.site_url + "/users/" + user.user_id;
            var renderedUserInfo = userInfoTemplate
                .replace(/details-href/g, href)
                .replace(/site-icon-url/g, user.on_site.icon_url)
                .replace(/user-gravatar-url/g, userGravatar)
                .replace(/user-display-name/g, user.display_name)
                .replace(/user-reputation/g, user.reputation)
                .replace(/user-abbreviated-reputation/g, userReputationAbbreviated);

            userdiv.innerHTML = renderedUserInfo;
            return userdiv;

        }

        var userInfoTemplate = " \
                <div class='user-gravatar32'> \
                    <img class='site-icon' height='32' width='32' alt='' src='site-icon-url' /> \
                </div> \
                <div class='user-gravatar32' title='click to view user profile'> \
                    <a href='details-href' target='_blank'> \
                        <img height='32' width='32' alt='' src='user-gravatar-url'> \
                    </a> \
                </div> \
                <div class='user-details'> \
                    <a href='details-href' target='_blank' title='click to view user profile'>user-display-name</a><br> \
                    <span title='reputation score user-reputation' class='reputation-score'>user-abbreviated-reputation</span> \
                </div>";

                
                
    </script>

</head>
<body>
    <div class="container">
        <div>
            <h1>
                Stack Users lite</h1>
            <p>
                Search for users on all Stack Exchange sites and view their associated accounts</p>
            <div id="input-container">
                <input type="text" id="user-name" />&nbsp;&nbsp;<input type="button" value="find user"
                    id="find-user-button" onclick="doSearch();" />
                &nbsp;&nbsp;<input type="checkbox" id="exact-match" /><label for="exact-match">Exact
                    Match</label>
            </div>
            <div id="loading-mask">
                <br />
                <h4>
                    Loading...</h4>
                <h5 id="loading-mask-message">
                    Please Wait...</h5>
                <br />
                <input type="button" value="Cancel" onclick="cancelSearch()" />
            </div>
            <div style="font-size: 10px;">
                <span>HINT: search term 'ben' will find 'ben', 'alanben', 'Antoine Benkemoun' etc etc</span><br />
                <span>NOTE: results are limited to the first 50 matches per site. If you can't find
                    who you are looking for you <i>probably</i> aren't being specific enough.</span>
            </div>
        </div>
        <p>
            &nbsp;</p>
        <h3>
            Associated Users</h3>
        <hr />
        <div style="clear: both">
            &nbsp;</div>
        <div id="associated-users">
        </div>
        <div style="clear: both">
            &nbsp;</div>
        <h3>
            Unassociated Users</h3>
        <hr />
        <div style="clear: both">
            &nbsp;</div>
        <div id="unassociated-users">
        </div>
        <div style="clear: both">
            &nbsp;</div>
        <div id="footer">
            <div class="footerdiv">
                View log in <a href="javascript:(function(F,i,r,e,b,u,g,L,I,T,E){if(F.getElementById(b))return;E=F[i+'NS']&amp;&amp;F.documentElement.namespaceURI;E=E?F[i+'NS'](E,'script'):F[i]('script');E[r]('id',b);E[r]('src',I+g+T);E[r](b,u);(F[e]('head')[0]||F[e]('body')[0]).appendChild(E);E=new%20Image;E[r]('src',I+L);})(document,'createElement','setAttribute','getElementsByTagName','FirebugLite','4','firebug-lite.js','releases/lite/latest/skin/xp/sprite.png','https://getfirebug.com/','#startOpened');">
                    Firebug Lite</a></div>
            <div class="footerdiv">
                Stack Users lite was built using only <a href="http://stackapps.com/questions/494"
                    target="_blank">SOAPI.JS</a>, an intuitive JavaScript wrapper library for the
                <a href="http://stackapps.com/questions/2/getting-started-with-the-api" target="_blank">
                    Stack Overflow API</a><br />
            </div>
            <div class="footerdiv">
                No jQuery scripts where harmed in the making of Stack Users lite.</div>
            <div class="footerdiv">
                The source code for Stack Users lite is right here in the page.
            </div>
            <div class="footerdiv">
                View the source to see how easy it is to query the API using <a href="http://stackapps.com/questions/494"
                    target="_blank">SOAPI.JS</a>
            </div>
            <div class="copyright">
                &copy; 2010 Sky Sanders - Stack Users lite is licensed under GPL version 2 open
                source license.</div>
        </div>
    </div>
</body>
</html>
